#include "Avalon/Codecs/AesEncoder.hpp"
#include <cryptopp/sha.h>
#include "Avalon/Codecs/AesDecoder.hpp"
#include "Avalon/IO/Buffer.hpp"

using namespace Avalon;
using namespace Avalon::Codecs;
using namespace Avalon::IO;
using namespace CryptoPP;

namespace {
  byte* CopyIV(const byte* source) {
    byte* copy = new byte[SHA::DIGESTSIZE];
    memcpy(copy, source, SHA::DIGESTSIZE);
    return copy;
  }
}

AesEncoder::AesEncoder(const SecByteBlock& key, const byte* iv)
    : m_key(key),
      m_iv(CopyIV(iv)),
      m_encoder(m_key, SHA256::DIGESTSIZE, m_iv.get()) {}

AesEncoder::~AesEncoder() {}

bool AesEncoder::IsEncodeInPlaceSupported() {
  return true;
}

void AesEncoder::Encode(const void* source, int sourceSize, void* destination,
    int destinationSize, int* encodedSize) {
  assert(destinationSize >= sourceSize);
  m_encoder.ProcessData(static_cast<byte*>(destination),
    static_cast<const byte*>(source), sourceSize);
  if(encodedSize != NULL) {
    *encodedSize = sourceSize;
  }
}

void AesEncoder::Encode(const void* source, int sourceSize,
    Buffer* destination, int* encodedSize) {
  int startingPoint = destination->GetSize();
  destination->Grow(sourceSize);
  m_encoder.ProcessData(reinterpret_cast<byte*>(destination->GetMutableData()
    + startingPoint), static_cast<const byte*>(source), sourceSize);
  if(encodedSize != NULL) {
    *encodedSize = sourceSize;
  }
}
